﻿using System;
using System.Collections.Generic;
using System.Text;

namespace OliveChess 
{
    using System.Collections;

    class Node : IComparable
    { 

        static int MIN_SCORE = -30000;
        static int MAX_SCORE = 30000;

        public List<Node> Children;

        //private List<Move> legalMoves;
        private int localScore;
        private int currentScore;
        private Position position;
        private Move previousMove;
        private int depth;
        //private int pvDepth;
        //private int key;
        //private String key;

        // async deletion indicator
        public bool toBeRemoved;

        public Node(Move move, Position position, int depth)
        {
            this.Children = null;
            //this.legalMoves = null;
            this.position = position;
            localScore = Engine.Evaluate(position);
            this.depth = depth;
            previousMove = move;
            //key = position.GetSimplifiedHashCode();
        }
        public Move GetPreviousMove()
        {
            return previousMove;
        }

        public int GetDepth()
        {
            return this.depth;
        }

        public bool IsLeave()
        {
            if (this.Children == null) return true;
            // if(IsCheckmate(position)...
            // if(IsStalemate(position)) return 0;
            return (this.Children.Count == 0);
        }

        public bool IsCreatedChildren()
        {
            return (this.Children != null);
        }
        /*
        public List<Move> GetLegalMoves()
        {
            return legalMoves;
        }
        */
        /**
         * Create children on level N-1, using hastable
         * @param nodeQueue Refence of node stack to feed
         */
        public int CreateChildren(Queue<Node> nodeQueue)
        {
            if (this.Children == null)
            {
                this.Children = new List<Node>();
                List<Move> legalMoves = Engine.GetLegalMoves(this.position);
                foreach (Move move in legalMoves)
                {
                    Position childBoard = new Position(this.position);
                    childBoard.Play(move);
                    //int key = childBoard.GetSHashCode();
                    //String key = childBoard.GetSimplifiedHashCode();
                    Node child = new Node(move, childBoard, this.depth + 1);
                    //Children.Sort();
                    this.Children.Add(child);
                    nodeQueue.Enqueue(child);
                }
                this.position = null;
                //System.Console.WriteLine("info depth " + this.depth);
                return legalMoves.Count;
            }
            return 0;
        }

        /**
         * Get instant value of the score previously calculated recursively
         * 
         * */
        public int GetScore()
        {
            return currentScore;
        }

        // WHITE ALPHABETA
        private int AlphaBetaWhite(int alpha, int beta, int currentDepth, int maxDepth)
        {
            if (currentDepth == 3)
            {
                int i = 0;
            }
            if (currentDepth >= maxDepth || this.IsLeave()) return localScore;
            int best = MAX_SCORE;
            foreach (Node child in this.Children)
            {
                // Correction : next ply is black
                //int score = child.AlphaBetaWhite(-beta, -alpha, currentDepth + 1, maxDepth);
                int score = child.AlphaBetaBlack(-beta, -alpha, currentDepth + 1, maxDepth);
                if (score < best)
                {
                    best = score;
                    if (best < beta)
                    {
                        beta = best;
                        if (alpha >= beta)
                        {
                            return best;
                        }
                    }
                }
                else
                {
                    // active AlphaBeta pruning
                    if (currentDepth < (maxDepth - 1)) child.ClearRecursively();
                    //Advance prunning (use statement: if(!brainMode == MATE_MODE) )
                    // TODO implement advance selective prunning
                }
            }

            return best;
        }

        // WHITE ALPHABETA
        private int AlphaBetaBlack(int alpha, int beta, int currentDepth, int maxDepth)
        {
            if (currentDepth >= maxDepth || this.IsLeave()) return localScore;

            int best = MIN_SCORE;
            foreach (Node child in this.Children)
            {
                // Correction : next ply is white
                //int score = child.AlphaBetaBlack(-beta, -alpha, currentDepth + 1, maxDepth);
                int score = child.AlphaBetaWhite(-beta, -alpha, currentDepth + 1, maxDepth);
                if (score > best)
                {
                    best = score;
                    if (best > alpha)
                    {
                        alpha = best;
                        if (alpha >= beta)
                        {
                            return best;
                        }
                    }

                }
                else
                {
                    // active AlphaBeta pruning
                    if (currentDepth < (maxDepth - 1)) child.ClearRecursively();
                }
            }
            return best;
        }
        /*
        public String GetSimplifiedHashCode()
        {
            return key;
        }
        */
        public void UpdateScore(int maxDepth, bool color)
        {
            //currentScore = this.AlphaBeta(MIN_SCORE, MAX_SCORE, 1, maxDepth, color);
            if (color)
            {
                // Correction : next ply is black
                //currentScore = this.AlphaBetaWhite(MIN_SCORE, MAX_SCORE, 1, maxDepth);
                currentScore = this.AlphaBetaBlack(MIN_SCORE, MAX_SCORE, 1, maxDepth);
            }
            else
            {
                // Correction : next ply is white
                //currentScore = this.AlphaBetaBlack(MIN_SCORE, MAX_SCORE, 1, maxDepth);
                currentScore = this.AlphaBetaWhite(MIN_SCORE, MAX_SCORE, 1, maxDepth);
            }
        }

        public void ClearRecursively()
        {
            this.toBeRemoved = true;
            if (this.Children != null)
            {
                foreach (Node node in this.Children)
                {
                    node.ClearRecursively();
                }
            }
            if (Children != null) this.Children.Clear();
        }

        // return high scores first
        public int CompareTo(object obj)
        {
            return ((Node)obj).localScore - this.localScore;
        }
    }
}


